﻿namespace EyeOpen.Mvc.DataEntry.Test
{
	using System;
	using System.Collections.Generic;
	using System.Linq;

	using EyeOpen.Data;
	using EyeOpen.DataEntry.Data;
	using EyeOpen.DataEntry.Domain;
	using EyeOpen.DataEntry.Web.Mvc;
	using EyeOpen.Domain;
	using EyeOpen.Web.Mvc.Models;

	using Microsoft.VisualStudio.TestTools.UnitTesting;

	using Moq;

	using SharpTestsEx;

	[TestClass]
	public class CustomerControllerTest
	{
		[TestMethod]
		public void UpdateCustomerAndCheck()
		{
			const int OldTurnover = 2000;
			const int NewTurnover = 3000;

			var customer = 
				new Customer
					{
						Id = Guid.NewGuid(),
						Name = "Bill",
						Acquired = DateTime.Now,
						Turnover = OldTurnover
					};

			using (var uow = CreateUow(customer)) 
			{
				CheckTurnover(OldTurnover, uow.CustomerRepository);

				new CustomerController(uow)
					.Update(
						new CustomerModel 
							{ 
								Id = customer.Id,
								Name = customer.Name,
								Acquired = customer.Acquired,
								Turnover = NewTurnover
							});

				CheckTurnover(NewTurnover, uow.CustomerRepository);
			}
		}

		private void CheckTurnover(int turnover, IQueryable<Customer> repository)
		{
			repository
				.Single()
				.Turnover
				.Should()
				.Be
				.EqualTo(turnover);
		}

		private IShopUnitOfWork CreateUow(params Customer[] collection) 
		{
			var uow = new Mock<IShopUnitOfWork>();

			uow
				.Setup(x => x.CustomerRepository)
				.Returns(this.GetRepository(collection));

			return uow.Object;
		}

		private IRepository<T> GetRepository<T>(params T[] collection) 
			where T : class, IEntity
		{
			var mockRepository = new Mock<IRepository<T>>();

			var list = new List<T>(collection);

			var queryable =
				list
					.AsQueryable();

			mockRepository
				.SetupGet(x => x.Provider)
				.Returns(queryable.Provider);

			mockRepository
				.SetupGet(x => x.Expression)
				.Returns(queryable.Expression);

			mockRepository
				.Setup(x => x.Add(It.IsAny<T>()))
				.Callback<T>(list.Add);

			mockRepository
				.Setup(x => x.Remove(It.IsAny<T>()))
				.Callback<T>(x => list.Remove(x))
				.Returns(true);

			mockRepository
				.Setup(x => x.Update(It.IsAny<T>()))
				.Callback<T>(x => 
					{
						{
							var position = -1;

							for (var i = 0; i < list.Count; i++)
							{
								if (!list[i].Id.Equals(x.Id))
								{
									continue;
								}

								position = i;
								break;
							}

							if (position == -1)
							{
								throw new Exception("Object not found.");
							}

							list[position] = x;
						} 
					});

			return mockRepository.Object;
		}
	}
}